package com.server.Tomcat.service.service_impl;

import com.proto_java.PBAccountNumber;
import com.proto_java.PBChatList;
import com.proto_java.PBGroupInfo;
import com.proto_java.PBInit;
import com.proto_java.proto_main.ProtobufPackage;
import com.server.Tomcat.service.AccountNumber;
import com.server.mongodb.domain.MGChatHistory;
import com.server.mongodb.domain.MGGroup;
import com.server.mongodb.domain.MGUser;
import com.server.mongodb.mapper.UserManageImpl;
import com.server.tools.Code;
import com.server.tools.JWTTools;
import com.server.tools.ProtoBufTools;
import com.server.tools.PublicUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.server.tools.ProtoBufTools.getOneChatHistory;

@Service
public class AccountNumberImpl implements AccountNumber {

    @Autowired
    UserManageImpl userManage;

    @Override
    public byte[] login(PBAccountNumber.AccountNumber data) {
        MGUser user = userManage.selectUser(data.getUid(), data.getPassword());
        // 验证不成功,直接返回
        return user==null?
                // 查询为null则返回异常
                ProtoBufTools.getResponseClass(Code.SELECT_ERR,"账号不存在")
                // 如果正常则填充内容返回数据
                : ProtobufPackage.PackageInfo.newBuilder()
                .setCode(Code.OK)
                .setMsg("登录成功！")
                .setToken(JWTTools.createToken(user.getUid())).build().toByteArray();
    }

    @Override
    public byte[] init(Long userUid) {
        MGUser user = userManage.selectUser(userUid);
        // 验证不成功,直接返回
        if(null == user){
            return ProtoBufTools.getResponseClass(Code.SELECT_ERR,"账号不存在");
        }

        // 创建初始化构建对象
        PBInit.Init.Builder initbuilder = PBInit.Init.newBuilder();
        // 先填充单条数据
        initbuilder.setName(user.getName())
                .setUid(user.getUid())
                // 调取工具类传入地址提取头像
                .setHeadImage(PublicUtils.getFile(user.getHeadImage()));

        // 读取好友及其群的未读消息,把它们合并起来
        Map<Long, Integer> friendUnread = userManage.getListUnreadMsg(user.getFriendUid(), user.getUid(),false);
        Map<Long, Integer> groupUnread = userManage.getListUnreadMsg(user.getGroupUid(), user.getUid(),true);

        // 做一下null值判定
        if(friendUnread==null){
            friendUnread=new HashMap<>();
        } else if (groupUnread!=null) {
            friendUnread.putAll(groupUnread);
        }
        // 拿到所有的有聊天记录的对象uid
        List<Long> getGroupAndFriendHaveChatHistory=userManage.getGroupAndFriendHaveChatHistory(
                user.getFriendUid(),user.getGroupUid(),userUid);

        // 将好友和群有过聊天记录的对象合并后的列表与用户uid传进去,得到所有好友和群的最新一条聊天记录
        List<MGChatHistory> initListHistory = userManage.getInitListHistory(getGroupAndFriendHaveChatHistory, user.getUid());
        // 得到所有需要的消息列表数据
        List<PBChatList.ChatList> initData = getChatList(
                initListHistory, friendUnread, user.getUid());
        // 整个List填充进去,并构建完整对象
        initbuilder.addAllChatList(initData).build();

        // 包上结构外壳,以及填充外壳需要的数据
        ProtobufPackage.PackageInfo lastData = ProtobufPackage.PackageInfo.newBuilder()
                .setCode(Code.OK)
                .setMsg("初始化信息成功!")
                .setInit(initbuilder).build();
        return lastData.toByteArray();
    }


    @Override
    public byte[] register(String name , String password){
        // 操作数据库注册
        Long uid = userManage.register(name, password);
        // 返回结果
        return uid ==null?
                ProtoBufTools.getResponseClass(Code.INSERT_ERR,"新增用户失败")
                :ProtobufPackage.PackageInfo.newBuilder()
                .setCode(Code.OK)
                .setMsg("用户创建成功!")
                .setToken(JWTTools.createToken(uid)).build().toByteArray();
    }


    @Override
    public byte[] searchUid(Long uid) {
        MGGroup mgGroupObject = userManage.selectGroup(uid);
        // 如果不是群消息则查询用户集合
        if(mgGroupObject==null){
            MGUser mgUser = userManage.selectUser(uid);
            // 如果既不是群uid也不是用户uid则返回异常码
            return mgUser==null? ProtoBufTools.getResponseClass(Code.SELECT_ERR,"未找相关到信息")
                    : ProtobufPackage.PackageInfo.newBuilder()
                    .setCode(200)
                    .setMsg("查询成功")
                    .setAccountNumber(PBAccountNumber.AccountNumber.newBuilder()
                            .setUid(uid)
                            .setName(mgUser.getName())
                            .setImage(PublicUtils.getFile(mgUser.getHeadImage()))
                            .build()).build().toByteArray();
        }
        // 如果是群就填充群内容
        return ProtobufPackage.PackageInfo.newBuilder()
                .setCode(200)
                .setMsg("查询成功")
                .setGroupInfo(PBGroupInfo.GroupInfo.newBuilder()
                        .setUid(uid)
                        .setName(mgGroupObject.getName())
                        .setHeadImage(PublicUtils.getFile(mgGroupObject.getHeadImage()))
                        .build()).build().toByteArray();
    }

    @Override
    public byte[] deleteAccount(Long uid) {

       Long modified= userManage.deleteAccount(uid); // 返回被修改的条数
        return modified==1? ProtoBufTools.getResponseClass(Code.OK,"注销成功")
                :ProtoBufTools.getResponseClass(Code.DELETE_ERR,"注销失败");
    }

    @Override
    public byte[] updatePassword(Long uid, String password, String newPassword) {
        Long modified=userManage.updatePassword(uid,password,newPassword);
        if(modified==-1){
            return ProtoBufTools.getResponseClass(Code.SELECT_ERR,"旧密码错误");
        }
        return modified==1?
                ProtoBufTools.getResponseClass(Code.OK,"修改成功")
                :ProtoBufTools.getResponseClass(Code.UPDATE_ERR,"修改失败");
    }

    @Override
    public byte[] updateHeadImageOrName(Long uid, String name, String image) {

        String type; // 图片格式
        String imageUrl; // 图片保存地址
        MGUser user=userManage.selectUser(uid); // 拿一下旧数据,下面会用到

        // 先看一下是否需要更新头像
        if(image!=null && !"".equals(image)){
            if (image.contains(";base64,")) {
                String formatPart = image.substring(image.indexOf("image/") + 6, image.indexOf(";base64,"));
                if ("png".equals(formatPart)) {
                    type="png";
                } else if ("jpeg".equals(formatPart) || "jpg".equals(formatPart)) {
                    type="jpg";
                }else{
                    return ProtoBufTools.getResponseClass(Code.UPDATE_ERR,"图片格式异常");
                }
                imageUrl="/headImage/headIcon"+uid+"."+type; // 存储地址
                PublicUtils.setFile(imageUrl,image);
            }else{
                return ProtoBufTools.getResponseClass(Code.UPDATE_ERR,"base64数据异常");
            }
        }else{
            // 如果没有图片则用之前的内容
            imageUrl =user.getHeadImage();
        }

        // 看一下是否需要修改昵称
        if(name==null || "".equals(name)){
            name =user.getName();
        }
        return userManage.updateHeadImageOrName(uid,name,imageUrl)==1?
                ProtoBufTools.getResponseClass(Code.OK,"修改成功")
                :ProtoBufTools.getResponseClass(Code.UPDATE_ERR,"修改失败");
    }

    @Override
    public byte[] createGroup(Long uid, String name) {
        // 操作数据库注册
        MGGroup group = userManage.createGroup(uid, name);

        if(group ==null){
           return ProtoBufTools.getResponseClass(Code.INSERT_ERR,"创建群聊失败");
        }
        // 填充数据
        PBGroupInfo.GroupInfo lastData=PBGroupInfo.GroupInfo.newBuilder()
                .setName(group.getName())
                .setUid(group.getUid())
                .setHeadImage(group.getHeadImage()).build();

        // 返回结果
        return ProtobufPackage.PackageInfo.newBuilder()
                .setCode(Code.OK)
                .setMsg("创建群聊成功!")
                .setGroupInfo(lastData).build().toByteArray();
    }


    /**
     * 整合初始化需要的消息列表内容,并返回该列表
     * 需要经过筛选整理好的数据,直可以接填充进去的。比如聊天记录,这里只要每个人/群的最新的一条聊天数据
     * @param descendingOrderList 每个有过聊天记录的好友/群的最新一条消息数据集合
     * @param unreadMsg 包含所有好友/群的uid和未读消息的Map,注意键值为<uid,对应的未读消息总条数>
     * @param userUid 用户uid
     * @return 每个对象最新一条聊天记录的List
     */
    public  List<PBChatList.ChatList> getChatList(List<MGChatHistory> descendingOrderList,
                                                        Map<Long,Integer> unreadMsg, Long userUid){
        List<PBChatList.ChatList> lastData = new ArrayList<>();

        // 仅把这里descendingOrderList中的数据封装,里面没有说明这个群没发过任何消息
        for(MGChatHistory p: descendingOrderList){
            Long uid; // 列表对象uid
            String name; // 列表对象名字
            String headImage;// 列表对象头像
            boolean exist; // 该uid是否正常使用

            // 如果是群消息,就直接填充群消息即可
            if(p.getGroupUid()!=null){
                uid=p.getGroupUid();
                name=p.getGroupName();
                headImage=PublicUtils.getFile(p.getGroupHeadImage());
                exist=userManage.selectGroup(uid)!=null;
            }else{
                // 判断谁是好友或者群,谁是用户自己,通过这个结果去选择将哪个对象作为列表对象填充
                boolean userControl = userUid.equals(p.getGetUserUid());
                // 如果这个用户是接收方,那么发送方就是好友,反过来接收方就是好友,其余数据同理
                uid = userControl ? p.getSendUserUid() : p.getGetUserUid();
                name = userControl ? p.getSendUserName() : p.getGetUserName();
                headImage = userControl ? PublicUtils.getFile(p.getSendUserHeadImage()) : PublicUtils.getFile(p.getGetUserHeadImage());
                exist=userManage.selectUser(userControl ? p.getSendUserUid() : p.getGetUserUid())!=null;
            }

            // 把数据库查到的所有数据都填充进list
            lastData.add(PBChatList.ChatList.newBuilder()
                    .setExist(exist)
                    .setUid(uid)
                    .setHeadImage(headImage)
                    .setName(name)
                    .setLastDate(PublicUtils.DateConvertString(p.getSendDate(),"yyyy-MM-dd HH:mm:ss"))
                    .setChatHistory(getOneChatHistory(p))
                    .setUnreadMsg(unreadMsg.get(uid)).build());
        }
        return lastData;
    }


}
